#include "Client.h"
#include "Buffer.h"
#include "Mutex.h"
#include "Event.h"
#include "ThreadPool.h"
#include "AdminUserManager.h"

using namespace AgoraServer;

Client::Client(int id, AgoraCore::Connection*	cnt)
: _id(id), _cntSound(0), _cntTxtAdm(cnt), _availableToSendSound(0), _availableToSendTxtAdm(0), _sendLoop(true)
{
	this->_buffSound = new Buffer(20000);
	this->_buffSendSound = new Buffer(20000);
	this->_lockSendSound = new Mutex();
	this->_eventBufferSound = new Event();
	this->_eventDestructorSound = new Event();
	this->_buffTxtAdm = new Buffer(20000);
	this->_buffSendTxtAdm = new Buffer(20000);
	this->_lockSendTxtAdm = new Mutex();
	this->_eventBufferTxtAdm = new Event();
	this->_eventDestructorTxtAdm = new Event();

	this->_buffCmdAdmData = new Buffer(20000);
	this->_buffCmdAdmSend = new Buffer(20000);

	ThreadPool::Request *rqt = new ThreadPool::Request();
	rqt->function = &Client::SendDataTxtAdm;
	rqt->autoFree = true;
	rqt->parameters = this;
	ThreadPool::GetThreadPool()->AddRequest(rqt);
}



Client::~Client()
{
	this->_sendLoop = false;
	this->_eventBufferSound->Set();
	this->_eventDestructorSound->Wait();
	this->_eventBufferTxtAdm->Set();
	this->_eventDestructorTxtAdm->Wait();
	delete this->_buffSound;
	delete this->_buffSendSound;
	delete this->_lockSendSound;
	delete this->_eventBufferSound;
	delete this->_eventDestructorSound;
	delete this->_buffTxtAdm;
	delete this->_buffSendTxtAdm;
	delete this->_lockSendTxtAdm;
	delete this->_eventBufferTxtAdm;
	delete this->_eventDestructorTxtAdm;
}

void	Client::SetConnectionSound(AgoraCore::Connection* cnt)
{
	_cntSound = cnt;
	ThreadPool::Request *rqt = new ThreadPool::Request();
	rqt->function = &Client::SendDataSound;
	rqt->autoFree = true;
	rqt->parameters = this;
	ThreadPool::GetThreadPool()->AddRequest(rqt);
}


IBuffer* Client::GetBufferSound()
{
	return (this->_buffSound);
}

IBuffer* Client::GetBufferTxtAdm()
{
	return (this->_buffTxtAdm);
}

AgoraCore::Connection*	Client::GetConnectionTxtAdm()
{
	return (this->_cntTxtAdm);
}

AgoraCore::Connection*	Client::GetConnectionSound()
{
	return (this->_cntSound);
}


int	Client::GetId()
{
	return (this->_id);
}

unsigned int	Client::SendBufferSound(void* data, unsigned int size)
{
	this->_lockSendSound->Lock();
	if (this->_buffSendSound->SizeMax() - this->_buffSendSound->Size() < size)
	{
		this->_lockSendSound->Unlock();
		return (1);
	}
	if (this->_buffSendSound->Write(data, size) >= 0)
	{
		this->_availableToSendSound += size;
		this->_eventBufferSound->Set();
	}
	this->_lockSendSound->Unlock();
	return (0);
}

void	Client::SendDataSound(void* client)
{
	Client*			clt = reinterpret_cast<Client*>(client);
	unsigned int	size;
	unsigned int	sentSize;
	void*			data;
	timeval			tm;


	while (clt->_sendLoop)
	{
		clt->_eventBufferSound->Wait();
		clt->_lockSendSound->Lock();
		size = clt->_availableToSendSound;
		clt->_lockSendSound->Unlock();
		data = clt->_buffSendSound->Read(size, false);
		tm.tv_sec = 1;
		tm.tv_usec = 0;
		sentSize = size;
		clt->_cntSound->SendData(data, &sentSize, &tm);
		
		clt->_lockSendSound->Lock();
		if (sentSize == clt->_availableToSendSound)
		{
			clt->_eventBufferSound->Reset();
		}
		clt->_availableToSendSound -= sentSize;
		clt->_buffSendSound->Delete(sentSize);
		clt->_lockSendSound->Unlock();
	}
	clt->_eventDestructorSound->Set();
}


unsigned int	Client::SendBufferTxtAdm(void* data, unsigned int size)
{
	this->_lockSendTxtAdm->Lock();
	if (this->_buffSendTxtAdm->SizeMax() - this->_buffSendTxtAdm->Size() < size)
	{
		this->_lockSendTxtAdm->Unlock();
		return (1);
	}
	if (this->_buffSendTxtAdm->Write(data, size) >= 0)
	{
		this->_availableToSendTxtAdm += size;
		this->_eventBufferTxtAdm->Set();
	}
	this->_lockSendTxtAdm->Unlock();
	return (0);
}

void	Client::SendDataTxtAdm(void* client)
{
	Client*			clt = reinterpret_cast<Client*>(client);
	unsigned int	size;
	unsigned int	sentSize;
	void*			data;
	timeval			tm;


	while (clt->_sendLoop)
	{
		clt->_eventBufferTxtAdm->Wait();
		clt->_lockSendTxtAdm->Lock();
		size = clt->_availableToSendTxtAdm;
		clt->_lockSendTxtAdm->Unlock();
		data = clt->_buffSendTxtAdm->Read(size, false);
		tm.tv_sec = 1;
		tm.tv_usec = 0;
		sentSize = size;
		clt->_cntTxtAdm->SendData(data, &sentSize, &tm);
		clt->_lockSendTxtAdm->Lock();
		if (sentSize == clt->_availableToSendTxtAdm)
		{
			clt->_eventBufferTxtAdm->Reset();
		}
		clt->_availableToSendTxtAdm -= sentSize;
		clt->_buffSendTxtAdm->Delete(sentSize);
		clt->_lockSendTxtAdm->Unlock();
	}
	clt->_eventDestructorTxtAdm->Set();
}

IBuffer*				Client::GetBufferCmdAdmData()
{
	return this->_buffCmdAdmData;
}

IBuffer*				Client::GetBufferCmdAdmSend()
{
	return this->_buffCmdAdmSend;
}

InfoAdmin&				Client::GetInfoCmd()
{
	return this->_infoCmd;
}
